<template>
    <div class="flow-viewer-container">
      <a-layout-content class="flow-content">
        <flow-area
          ref="flowAreaRef"
          :dragInfo="dragInfo"
          :config="flowConfig"
          :data="flowData"
          :select="currentSelect"
          :selectGroup="currentSelectGroup"
          :plumb="plumb"
          :currentTool="currentTool"
          :readonly="true"
        />
      </a-layout-content>
    </div>
  </template>
  
  <script lang="ts" setup>
    import { jsPlumb } from 'jsplumb';
    import { reactive, ref, onMounted, nextTick, unref } from 'vue';
    import { cloneDeep } from 'lodash-es';
    import FlowArea from './modules/flowArea.vue';
    import { tools } from '../config/tools';
    import { IDragInfo, INode, ILink, ITool } from '../type/index';
    import { ActionsTypeEnum, FlowStatusEnum } from '../type/enums';
    import { flowConfig as defaultFlowConfig } from '../config/flow';
  
    const props = defineProps({
      flowDataStr: {
        type: String,
        default: '',
      },
    });
  
    // 流程配置
    const flowConfig = ref(cloneDeep(defaultFlowConfig));
  
    // 流程实例
    const plumb = ref();
  
    // 当前工具类型 - 设置为只读工具
    const currentTool = ref<ITool>(tools.find(t => t.type === ActionsTypeEnum.DRAG) || tools[0]);
  
    // 画布Ref
    const flowAreaRef = ref();
  
    // 流程DSL
    const flowData = reactive<Recordable>({
      nodeList: [],
      linkList: [],
      attr: {
        id: '',
      },
      config: {
        showGrid: true,
        showGridText: '隐藏网格',
        showGridIcon: 'EyeOutlined',
      },
      status: FlowStatusEnum.CREATE,
    });
  
    // 当前选择节点 - 只读模式下不需要实际选择
    const currentSelect = ref<INode | ILink>();
  
    // 当前选择组 - 只读模式下不需要实际选择
    const currentSelectGroup = ref<INode[]>([]);
  
    // 拖拽组件元素信息 - 只读模式下不需要拖拽
    const dragInfo = reactive<IDragInfo>({
      type: null,
      belongTo: null,
    });
  
    // 渲染流程
    async function loadFlow(str = '') {
      if (!str) return;
      
      // 清空现有数据
      flowData.nodeList = [];
      flowData.linkList = [];
      
      await nextTick();
      const loadData = JSON.parse(str);
      flowData.attr = loadData.attr;
      flowData.config = loadData.config;
      flowData.status = FlowStatusEnum.LOADING;
      
      unref(plumb).batch(async () => {
        // 加载节点
        const nodeList = loadData.nodeList;
        nodeList.forEach((node: INode) => {
          flowData.nodeList.push(node);
        });
  
        await nextTick();
        
        // 加载连线
        const linkList = loadData.linkList;
        linkList.forEach((link: ILink) => {
          flowData.linkList.push(link);
          let conn = unref(plumb).connect({
            source: link.sourceId,
            target: link.targetId,
            anchor: unref(flowConfig).jsPlumbConfig.anchor.default,
            connector: [link.cls.linkType, unref(flowConfig).jsPlumbInsConfig.Connector?.[1]],
            paintStyle: {
              stroke: link.cls.linkColor,
              strokeWidth: link.cls.linkThickness,
            },
          });
          
          if (link.label !== '') {
            conn.setLabel({
              label: link.label,
              cssClass: `linkLabel ${conn.canvas.id}`,
            });
          }
        });
  
        flowData.status = FlowStatusEnum.MODIFY;
      }, true);
  
      // 重置画布位置
      if (unref(flowAreaRef)?.container) {
        unref(flowAreaRef).container.pos = {
          top: 0,
          left: 0,
        };
      }
    }
  
    // 实例化JsPlumb
    function initJsPlumb() {
      plumb.value = jsPlumb.getInstance(unref(flowConfig).jsPlumbInsConfig);
      
      // 禁用拖拽和编辑功能
      unref(plumb).importDefaults({
        ConnectionsDetachable: false,
      });
    }
  
    // 对外暴露加载流程数据的方法
    defineExpose({
      loadFlow
    });
  
    onMounted(() => {
      // 实例化JsPlumb
      initJsPlumb();
      
      // 如果有传入数据，则加载
      if (props.flowDataStr) {
        loadFlow(props.flowDataStr);
      }
    });
  </script>
  
  <style scoped>
  .flow-viewer-container {
    width: 100%;
    height: 100%;
    position: relative;
  }
  
  .flow-content {
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
    background-color: #f0f2f5;
  }
  </style>